package cn.com.easy.permission.option_log;

import java.io.IOException;
import java.io.Serializable;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import cn.com.easy.permission.job.SaveOptionLogModelJob;
import cn.com.easy.permission.model.OptionLogModel;
import cn.com.easy.permission.model.OptionLogModel.OPTION_STATUS_ENUM;
import cn.com.easy.persistence.BaseEntity;
import cn.com.easy.utils.DateUtils;
import cn.com.easy.utils.FastJSONUtils;
import cn.com.easy.utils.PropertiesUtils;
import cn.com.easy.utils.SpringContextHolder;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * jpa拦截器
 * 
 * @author nibili 2017年12月20日
 * 
 */
public class OptionLogInterceptor extends EmptyInterceptor {

	/** */
	private static final long serialVersionUID = 6205503422418401605L;

	private Logger logger = LoggerFactory.getLogger(OptionLogInterceptor.class);

	/** 操作日志dao */
	private SaveOptionLogModelJob saveOptionLogModelJob = null;
	/** 要排除不监听的实体 */
	private List<String> excludeEntityCalssList = Lists.newArrayList();
	/** 必须监听的实体 */
	private List<String> includeEntityCalssList = Lists.newArrayList();

	@Override
	public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {

		try {
			//
			this.init();
			// 删除
			String entityClassName = entity.getClass().getName();
			if (this.isExcludeClassName(entityClassName) == false) {
				BaseEntity baseEntity = (BaseEntity) entity;
				OptionLogModel optionLogModel = new OptionLogModel();
				// 一、类名
				optionLogModel.setClassName(entity.getClass().getName());
				//
				if (StringUtils.isNotBlank(baseEntity.getLastModifyBy()) == true) {
					// 如果最后修改人不为空使用最后修改人做为创建人
					optionLogModel.setCreateBy(baseEntity.getLastModifyBy());
					optionLogModel.setCreateById(baseEntity.getLastModifyById());
				} else {
					optionLogModel.setCreateBy(baseEntity.getCreateBy());
					optionLogModel.setCreateById(baseEntity.getCreateById());
				}
				// 找出两组数组中的不同值
				List<Map<Object, Object>> mapList = this.findDifferent(previousState, currentState, propertyNames);
				// 二、原字段值
				String originalFieldValue = FastJSONUtils.toJsonString(mapList.get(0));
				optionLogModel.setOriginalFieldValue(originalFieldValue);
				// 三、 新字段值
				String newFieldValue = FastJSONUtils.toJsonString(mapList.get(1));
				optionLogModel.setNewFieldValue(newFieldValue);
				// 四、操作
				// 删除
				optionLogModel.setOptionStatus(OPTION_STATUS_ENUM.UPDATE.getValue());
				// 五、id
				optionLogModel.setEntityId((Long) id);

				long threadId = Thread.currentThread().getId();
				saveOptionLogModelJob.addModel(threadId, optionLogModel);

			}
		} catch (Exception ex) {
			logger.error("", ex);
		}

		return false;
	}

	@Override
	public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
		try {
			//
			this.init();
			// 删除
			String entityClassName = entity.getClass().getName();
			if (this.isExcludeClassName(entityClassName) == false) {
				BaseEntity baseEntity = (BaseEntity) entity;
				OptionLogModel optionLogModel = new OptionLogModel();
				// 一、类名
				optionLogModel.setClassName(entity.getClass().getName());
				//
				if (StringUtils.isNotBlank(baseEntity.getLastModifyBy()) == true) {
					// 如果最后修改人不为空使用最后修改人做为创建人
					optionLogModel.setCreateBy(baseEntity.getLastModifyBy());
					optionLogModel.setCreateById(baseEntity.getLastModifyById());
				} else {
					optionLogModel.setCreateBy(baseEntity.getCreateBy());
					optionLogModel.setCreateById(baseEntity.getCreateById());
				}
				// 二、原字段值
				optionLogModel.setOriginalFieldValue(FastJSONUtils.toJsonString(entity));
				// 三、操作
				// 删除
				optionLogModel.setOptionStatus(OPTION_STATUS_ENUM.DELETE.getValue());
				// 四、id
				optionLogModel.setEntityId((Long) id);

				long threadId = Thread.currentThread().getId();
				saveOptionLogModelJob.addModel(threadId, optionLogModel);

			}
		} catch (Exception ex) {
			logger.error("", ex);
		}

	}

	@Override
	public void postFlush(@SuppressWarnings("rawtypes") Iterator entities) {
		this.init();

		while (entities.hasNext()) {

			//
			Object entity = entities.next();
			System.out.println(FastJSONUtils.toJsonString(entity));
			if (entity instanceof BaseEntity) {
				try {
					BaseEntity baseEntity = (BaseEntity) entity;
					if (baseEntity.getVersion() != null && baseEntity.getVersion().longValue() > 0) {
						// 不是新增
						return;
					}
					String entityClassName = entity.getClass().getName();
					if (this.isExcludeClassName(entityClassName) == false) {

						OptionLogModel optionLogModel = new OptionLogModel();
						// 一、类名
						optionLogModel.setClassName(entity.getClass().getName());
						//
						if (StringUtils.isNotBlank(baseEntity.getLastModifyBy()) == true) {
							// 如果最后修改人不为空使用最后修改人做为创建人
							optionLogModel.setCreateBy(baseEntity.getLastModifyBy());
							optionLogModel.setCreateById(baseEntity.getLastModifyById());
						} else {
							optionLogModel.setCreateBy(baseEntity.getCreateBy());
							optionLogModel.setCreateById(baseEntity.getCreateById());
						}
						// 二、操作
						// 新增
						optionLogModel.setOptionStatus(OPTION_STATUS_ENUM.ADD.getValue());
						// 三、新字段值
						optionLogModel.setNewFieldValue(FastJSONUtils.toJsonString(entity));
						// 四、id
						optionLogModel.setEntityId(baseEntity.getId());

						long threadId = Thread.currentThread().getId();
						saveOptionLogModelJob.addModel(threadId, optionLogModel);
					}
				} catch (Exception ex) {
					logger.error("", ex);
				}
			}

		}

	}

	/**
	 * 是否排除的类名
	 * 
	 * @param className
	 * @return
	 * @author nibili 2017年12月22日
	 */
	private boolean isExcludeClassName(String className) {
		if (StringUtils.equals(className, "cn.com.easy.permission.model.OptionLogModel") == true) {
			// 操作日志要排除
			return true;
		}
		if (CollectionUtils.isEmpty(includeEntityCalssList) == false) {
			// 不为空，匹配的都不过滤，直接获取网站资源
			for (String patten : includeEntityCalssList) {
				if (className.matches(patten) == true) {
					return false;
				}
			}
		}
		if (CollectionUtils.isEmpty(excludeEntityCalssList) == false) {
			// 不为空，匹配的都不过滤，直接获取网站资源
			for (String patten : excludeEntityCalssList) {
				if (className.matches(patten) == true) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * 初始化
	 * 
	 * @author nibili 2017年12月21日
	 */
	private void init() {
		if (saveOptionLogModelJob == null) {
			saveOptionLogModelJob = SpringContextHolder.getBean(SaveOptionLogModelJob.class);
			// 不进行记录的实体集合
			try {
				Properties properties = PropertiesUtils.loadProperties("permission.properties");
				String value = properties.getProperty("option.log.interceptor.exclude.classes");
				if (StringUtils.isNotBlank(value) == true) {
					excludeEntityCalssList = Lists.newArrayList(StringUtils.split(value, ","));
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			// 必须记录的实体集合
			try {
				Properties properties = PropertiesUtils.loadProperties("permission.properties");
				String value = properties.getProperty("option.log.interceptor.include.classes");
				if (StringUtils.isNotBlank(value) == true) {
					includeEntityCalssList = Lists.newArrayList(StringUtils.split(value, ","));
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	//
	// /**
	// * 将属性名与属性值对应起来
	// *
	// * @param newState
	// * @param propertyNames
	// * @return
	// * @author nibili 2017年12月21日
	// */
	// private Map<String, Object> propertyNameValueMap(Object[] newState,
	// String[] propertyNames) {
	// Map<String, Object> map = Maps.newHashMap();
	// for (int i = 0, len = propertyNames.length; i < len; i++) {
	// map.put(propertyNames[i], newState[i]);
	// }
	// return map;
	// }

	/**
	 * 找出不同值的object
	 * 
	 * @param originalState
	 * @param newState
	 * @param propertyNames
	 * @return
	 * @author nibili 2017年12月21日
	 */
	private List<Map<Object, Object>> findDifferent(Object[] originalState, Object[] newState, String[] propertyNames) {
		//
		List<Map<Object, Object>> list = Lists.newArrayList();
		//
		Map<Object, Object> mapOriginal = Maps.newHashMap();
		Map<Object, Object> mapNew = Maps.newHashMap();
		//
		for (int i = 0, len = propertyNames.length; i < len; i++) {
			Object originalValue = originalState[i];
			Object newValue = newState[i];
			//
			String originalStringValue = "";
			String newStringValue = "";
			if (originalValue instanceof Date) {
				originalStringValue = DateUtils.formatDate((Date) originalValue, "");
				if (newValue != null) {
					newStringValue = DateUtils.formatDate((Date) newValue, "");
				}
			} else {
				originalStringValue = String.valueOf(originalValue);
				newStringValue = String.valueOf(newValue);
			}
			//
			if (StringUtils.equals(originalStringValue, newStringValue) == false) {
				mapOriginal.put(propertyNames[i], originalStringValue);
				mapNew.put(propertyNames[i], newStringValue);
			}
		}
		//
		list.add(mapOriginal);
		list.add(mapNew);
		//
		return list;
	}
}